package com.block.api.interceptor;

import cn.hutool.core.io.IoUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.servlet.ServletUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.block.api.reqbean.ReqBeanUtil;
import com.block.common.encrypt.enums.EncryptTypeEnum;
import com.block.common.encrypt.factory.EncryptFactory;
import com.block.common.exception.NotifyExceptionService;
import com.block.common.model.dto.EncryptKeyDTO;
import com.block.common.model.dto.RequestTimeDTO;
import com.block.common.model.vo.ResultInfoVO;
import com.block.common.service.*;
import com.block.common.util.HttpReturnUtil;
import com.block.db.entity.ApplicationInfo;
import com.block.db.entity.ChannelBaseInfo;
import com.block.db.entity.SourceBaseInfo;
import com.block.common.enums.InfoTypeEnum;
import org.slf4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.nio.charset.Charset;
import java.util.Date;


/**
 * 线索渠道 过滤器
 */
public class InitSourceInterceptor implements HandlerInterceptor {

	private static final Logger log = LogFactory.getSourceLog();
	private static final Logger logTime = LogFactory.getTimeLog();

	@Autowired
	ISourceBaseInfoService sourceBaseInfoService;
	@Autowired
	IChannelCommonService channelCommonService;

	@Autowired
	NotifyExceptionService notifyExceptionService;
	@Autowired
	IApplicationInfoService applicationInfoService;
	@Autowired
	StringRedisTemplate stringRedisTemplate;
	@Autowired
	ISystemRequestTimeRecordService systemRequestTimeRecordService;


//	private static String requestCountKey = "REQUEST:COUNT:KEY:";
//	private static String requestReturnCountKey = "REQUEST:RETURN:COUNT:KEY:{}:{}";
//
//	public static RateLimiter rateLimiter = RateLimiter.create(10);

	@Override
	public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
			throws Exception {

		String uri = request.getRequestURI();
		String ip= ServletUtil.getClientIP(request);
		try {

			String paramContent = IoUtil.read(request.getInputStream(), Charset.defaultCharset());
			log.info("【线索渠道】【请求地址】{}【请求参数】{}", uri, paramContent);

			JSONObject jsonObject = JSON.parseObject(paramContent);
			String channelCode = jsonObject.getString("channelCode");

			SourceBaseInfo sourceBaseInfo = sourceBaseInfoService.getSourceBaseInfoByCode(channelCode);
			if (ObjectUtil.isEmpty(sourceBaseInfo)){
				HttpReturnUtil.returnJson(response, ResultInfoVO.error("渠道信息为空，联系管理员"));
				return false;
			}
			if (ObjectUtil.equal(sourceBaseInfo.getStatus(), Integer.valueOf(0))){
				HttpReturnUtil.returnJson(response, ResultInfoVO.error("渠道状态不可用，联系管理员"));
				return false;
			}
			if (!StrUtil.equals(sourceBaseInfo.getType(), InfoTypeEnum.API.getValue()) &&
					!StrUtil.equals(sourceBaseInfo.getType(), InfoTypeEnum.APIB.getValue()) &&
					!StrUtil.equals(sourceBaseInfo.getType(), InfoTypeEnum.APIB_S.getValue())){
				HttpReturnUtil.returnJson(response, ResultInfoVO.error("渠道类型错误，联系管理员"));
				return false;
			}

//			if (StrUtil.equals("/apisource/source/checkUser", uri)){
//				// 请求数量
////				String redisKey = requestCountKey + channelCode;
////				String requestCount = stringRedisTemplate.opsForValue().get(redisKey);
//
////				boolean get = rateLimiter.tryAcquire(2, TimeUnit.SECONDS);
//				boolean get = rateLimiter.tryAcquire();
//				if (!get){
//					// 拦截掉的请求直接统计一下
//					String redisReturnKey = StrUtil.format(requestReturnCountKey , LocalDate.now().toString(), channelCode);
//					stringRedisTemplate.opsForValue().increment(redisReturnKey);
//					log.info("【线索渠道】超过请求个数【channelCode】{}【requestCount】{}【请求地址】{}【paramContent】{}", channelCode, uri, paramContent);
//					JSONObject returnObject = new JSONObject();
//					returnObject.put("status", "001");
//					returnObject.put("remark", "用户已存在");
//					HttpReturnUtil.returnJson(response, ResultInfoVO.success(returnObject));
//					return false;
//				}
//			}

			// 请求验签
			String requestNo = jsonObject.getString("requestNo");
			String timestamp = jsonObject.getString("timestamp");

			EncryptKeyDTO encryptKeyDTO = new EncryptKeyDTO();
			encryptKeyDTO.setAppCode(sourceBaseInfo.getChannelCode());
			encryptKeyDTO.setAppKey(sourceBaseInfo.getApiKey());
			encryptKeyDTO.setAppSecret(sourceBaseInfo.getApiSecret());
//			encryptKeyDTO.setPubKey(unionBaseInfo.getPubKey());
//			encryptKeyDTO.setPriKey(unionBaseInfo.getPriKey());

			//业务参数 解密
			JSONObject tranData = null;
			try {
				if (StrUtil.equals(channelCode, "F590OG")){
					tranData = jsonObject.getJSONObject("tranData");
				}else{
					tranData = EncryptFactory.getService(EncryptTypeEnum.AES.getValue()).decryptTranData(encryptKeyDTO, jsonObject);
				}

				log.info("【线索渠道】【解秘完数据】{}", JSON.toJSONString(tranData));
			}catch (Exception exception){
				exception.printStackTrace();
				HttpReturnUtil.returnJson(response, requestNo, ResultInfoVO.error("业务参数解密失败"));
				String content = StrUtil.format("【uri】{}【channelCode】{}【tranData】{}", uri, channelCode, tranData);
				notifyExceptionService.notifyNoticeInfo("SOURCE_REQUEST_TRANDATA", "线索业务数据解密异常", content, exception);
				return false;
			}

			if (ObjectUtil.isEmpty(tranData)){
				HttpReturnUtil.returnJson(response, requestNo, ResultInfoVO.error("业务参数解析失败"));
				return false;
			}

			ChannelBaseInfo channelBaseInfo = channelCommonService.getBaseInfoByCode(channelCode);

			ApplicationInfo applicationInfo = applicationInfoService.getAppInfoByAppCode(channelBaseInfo.getAppCode());

			request.setAttribute("tranData", tranData);
			request.setAttribute("requestNo", requestNo);
			request.setAttribute("sourceBaseInfo", sourceBaseInfo);
			request.setAttribute("channelBaseInfo", channelBaseInfo);
			request.setAttribute("applicationInfo", applicationInfo);
			request.setAttribute("uri", uri);
			request.setAttribute("startDate", new Date());
			request.setAttribute("ip", ip);
			request.setAttribute("tranDataBean", tranData.toJavaObject(ReqBeanUtil.getBeanClass(uri)));

			return  true;
		} catch (Exception exception){
			log.error("拦截器处理异常json...",exception);
			HttpReturnUtil.returnJson(response, ResultInfoVO.error("处理异常"));

			String content = StrUtil.format("【uri】{}", uri);
			notifyExceptionService.notifyNoticeInfo("SOURCE_REQUEST", "线索请求异常", content, exception);
			return  false;
		}
	}

	@Override
	public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
		HandlerInterceptor.super.postHandle(request, response, handler, modelAndView);

		String uri = (String) request.getAttribute("uri");
		try {
			Date startDate = (Date) request.getAttribute("startDate");
			SourceBaseInfo sourceBaseInfo = (SourceBaseInfo) request.getAttribute("sourceBaseInfo");

			JSONObject tranData = (JSONObject) request.getAttribute("tranData");

//			if (StrUtil.equals("/apisource/source/checkUser", uri)) {
//				String redisKey = requestCountKey + sourceBaseInfo.getChannelCode();
//				String count = stringRedisTemplate.opsForValue().get(redisKey);
//				if (ObjectUtil.isNotEmpty(count) && Integer.valueOf(count) > 0) {
//					stringRedisTemplate.opsForValue().decrement(redisKey);
//				}
//			}

			Date endDate = new Date();
			long execTime = endDate.getTime() - startDate.getTime();

			if (execTime > 2000){
				logTime.info("【uri】{}【execTime】{}【channelCode】{}【channelName】{}", uri, execTime, sourceBaseInfo.getChannelCode(), sourceBaseInfo.getChannelName());

//				OutputStream byteArrayOutputStream = (OutputStream) response.getOutputStream();
//				ByteArrayInputStream byteArrayInputStream =new ByteArrayInputStream(((ByteArrayOutputStream)byteArrayOutputStream).toByteArray());
//
//				int n = byteArrayInputStream.available();
//				byte[] bytes = new byte[n];
//				byteArrayInputStream.read(bytes, 0, n);
//				String resultInfo = new String(bytes, StandardCharsets.UTF_8);
//
//				System.out.println("压缩前数据：" + resultInfo);

				RequestTimeDTO timeDTO = new RequestTimeDTO();
				timeDTO.setBizType("SOURCE_REQUEST_RESPONSE");
				timeDTO.setBizName("线索请求响应");
				timeDTO.setExecTime(String.valueOf(execTime));
				timeDTO.setLineTime("1000");
				timeDTO.setParamInfo(JSON.toJSONString(tranData));
//				timeDTO.setResultInfo(resultInfo);
				timeDTO.setRemarkInfo(StrUtil.format("【uri】{}【channelCode】{}【channelName】{}", uri, sourceBaseInfo.getChannelCode(), sourceBaseInfo.getChannelName()));
				systemRequestTimeRecordService.saveRequestTime(timeDTO);
			}
		}catch (Exception exception){
			exception.printStackTrace();
			String content = StrUtil.format("【uri】{}", uri);
			notifyExceptionService.notifyNoticeInfo("SOURCE_RESPONSE", "请求返回", content, exception);
		}
	}

}
